/// Copyright (c) Microsoft Corporation.  All rights reserved.

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Win32;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Security;
using System.Diagnostics.CodeAnalysis;

namespace Microsoft.VSPowerToys.Common.TaskManager
{
    /// <summary>
    /// Implementation of IApplicationHostData which gathers information about possible install locations 
    /// for VSI contents.
    /// </summary>
    internal class ApplicationHostData : Microsoft.VisualStudio.ContentInstaller.IApplicationHostData
    {

        private string applicationName;
        private string dataFolder;
        private bool express;
        private string applicationPath;
        private string progId;

        /// <summary>
        /// Private constructor since this object should not be created by other sources
        /// </summary>
        private ApplicationHostData()
        {
        }

        /// <summary>
        /// Tries to execute the given command on the host. Prefers going through DTE object model first
        /// </summary>
        /// <param name="command">Command to execute</param>
        /// <remarks>We need to call GetTypeFromProgID thus FxCop warning is suppressed.</remarks>
        [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
        public bool ExecuteCommand(string command)
        {
            if (!String.IsNullOrEmpty(this.ProgId))
            {
                Type dteType = Type.GetTypeFromProgID(this.ProgId);
                if (dteType != null)
                {
                    EnvDTE.DTE dte = (EnvDTE.DTE)(Activator.CreateInstance(dteType, true));
                    dte.ExecuteCommand(command, String.Empty);
                    dte.Quit();
                    return true;
                }
            }
            if (!String.IsNullOrEmpty(this.ApplicationPath))
            {
                Process.Start(this.ApplicationPath, "/Command " + command);
                return true;
            }
            return false;
        }

        #region Static Members

        private static Dictionary<HostDataKey, Collection<ApplicationHostData>> hostDictionary = null;

        /// <summary>
        /// Gets the available host information for provided content type and version
        /// </summary>
        /// <param name="type"></param>
        /// <param name="version"></param>
        /// <returns></returns>
        public static Collection<ApplicationHostData> GetHostData(string type, string version)
        {
            if (hostDictionary == null) CollectApplicationHostData();
            HostDataKey key = new HostDataKey(type, version);
            if (hostDictionary.ContainsKey(key))
            {
                return hostDictionary[key];
            }
            else
            {
                return new Collection<ApplicationHostData>();
            }
        }

        /// <summary>
        /// Collects host data from registry.
        /// </summary>
        private static void CollectApplicationHostData()
        {
            try
            {
                hostDictionary = new Dictionary<HostDataKey, Collection<ApplicationHostData>>();
                RegistryKey communityContentKey =
                    Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\MSEnvCommunityContent\ContentTypes", false);
                if (communityContentKey == null) return;
                foreach (string contentType in communityContentKey.GetSubKeyNames())
                {
                    RegistryKey contentKey = communityContentKey.OpenSubKey(contentType + @"\ContentHosts", false);
                    if (contentKey == null) continue;
                    foreach (string version in contentKey.GetSubKeyNames())
                    {
                        RegistryKey versionKey = contentKey.OpenSubKey(version);
                        foreach (string hostName in versionKey.GetSubKeyNames())
                        {
                            RegistryKey hostKey = versionKey.OpenSubKey(hostName);
                            ApplicationHostData hostData = new ApplicationHostData();
                            hostData.express =
                                ((int)(hostKey.GetValue("ExpressVersion", 0, RegistryValueOptions.None))) == 1;
                            hostData.applicationName = (string)(hostKey.GetValue("ApplicationName", String.Empty));
                            string dataFolder = (string)(hostKey.GetValue("UserDataFolder", String.Empty));
                            dataFolder = System.Environment.ExpandEnvironmentVariables(dataFolder);
                            dataFolder = dataFolder.Replace("%VSMYDOCUMENTS%", System.Environment.GetFolderPath(Environment.SpecialFolder.Personal));
                            hostData.dataFolder = dataFolder;
                            hostData.progId = (string)(hostKey.GetValue("ProgID", String.Empty));
                            hostData.applicationPath = (string)(hostKey.GetValue("ApplicationPath", String.Empty));
                            HostDataKey dataKey = new HostDataKey(contentType, version);
                            if (!hostDictionary.ContainsKey(dataKey))
                            {
                                hostDictionary.Add(dataKey, new Collection<ApplicationHostData>());
                            }
                            hostDictionary[dataKey].Add(hostData);
                        }
                    }
                }
            }
            catch (SecurityException)
            {

            }
            catch (ArgumentException)
            {

            }
        }

        #endregion

        #region IApplicationHostData Members

        public System.Drawing.Bitmap ApplicationImage
        {
            get { throw new NotImplementedException(); }
        }

        public string ApplicationName
        {
            get { return this.applicationName; }
        }

        public string ApplicationPath
        {
            get { return this.applicationPath; }
        }

        public bool ExpressVersion
        {
            get { return this.express; }
        }

        public string ProgId
        {
            get { return this.progId; }
        }

        public string RegistryRoot
        {
            get { throw new NotImplementedException(); }
        }

        public string UserDataFolder
        {
            get { return this.dataFolder; }
        }

        #endregion

        /// <summary>
        /// Key to use in ApplicationHostData dictionary.
        /// </summary>
        private class HostDataKey
        {
            private string contentType;
            private string version;

            public HostDataKey(string type, string version)
            {
                this.contentType = type;
                this.version = version;
            }

            public override bool Equals(object obj)
            {
                HostDataKey other = obj as HostDataKey;
                if (other != null)
                {
                    return this.contentType.Equals(other.contentType) && this.version.Equals(other.version);
                }
                else
                {
                    return false;
                }
            }

            public override int GetHashCode()
            {
                return contentType.GetHashCode() + version.GetHashCode();
            }
        }
    }
}
